<?php declare(strict_types=1);
namespace app\logic;

use app\exception\auth\AccountOrPasswordError;
use app\exception\AuthFailure;
use app\exception\ObjectHasExists;
use app\exception\ParamsInvalidate;
use app\exception\Success;
use app\execption\auth\TokenMust;
use app\library\DefaultConfig;
use app\model\UserToken as UserTokenModel;
use app\facade\model\UserToken as FaUserTokenModel;
use app\facade\model\User as FaUserModel;
use app\model\UserToken;
use app\validate\User as UserValidate;
use clonelin\library\DateTime;
use think\Exception;
use think\facade\Config;
use think\facade\Session;
use think\helper\Str;

class User  extends Base {

    // Login
    public function login(){
        // Get POST Data
        $postData = $this->request->post();
        // Get Token Data
        $userToken = $this->getTokenByLogin($postData);
        // Return Token Data
        $userToken->hidden(['create_at','update_at','user_id']);
        // Login Success
        throw new Success($userToken);
    }

    // Get Token By Login Info
    public function getTokenByLogin(array $postData) : ?UserTokenModel {

        // Post Data Validate
        $validate = new UserValidate();
        $success = $validate->scene('login')->check($postData);
        if(!$success) {
            throw new ParamsInvalidate($validate->getError());
        }
        // Account Is Exists
        $user =  FaUserModel::getUserByLogin($postData);
        if(!$user){
            throw new AccountOrPasswordError();
        }

        if($user['status'] == 0) {
            throw new AuthFailure('account disabled');
        }

        // User ID
        $userId = $user['user_id'];

        // Session
        Session::set(DefaultConfig::SESSION_USER_ID_NAME,$userId);
        Session::set(DefaultConfig::SESSION_IS_SUPER,$user['is_super']);
        // Get Token Expire Time Minutes
        $minutes =  Config::get('app.token_expire_time_minutes',DefaultConfig::TokenExpireTimeMinutes);

        $now = DateTime::getCurrentDateTime();
        $expireTime = DateTime::getAfterMinutesOfNow($minutes);
        // New Token
        $tokenValue = md5(Str::random(8).'#'.$userId);
        // Create New Token
        $tokenData = [
            'update_at'=>$now,
            'expire_at'=>$expireTime,
            'create_at'=>$now,
            'user_id'=>$userId,
            'token'=>$tokenValue
        ];
        // New Token
        $token = FaUserTokenModel::create($tokenData,[],true);

        return $token;
    }


    // Get User By User ID
    public function getUserByUserId(){

        $user = FaUserModel::getUserByUserId($this->userId);
        $user->hidden(['user_id','password','create_at','update_at','delete_at']);
        return $user;
    }


    public function getUserList(){
        //
        $page = $this->request->param('page',DefaultConfig::CURRENT_PAGE);
        $limit = $this->request->param('limit',DefaultConfig::PAGE_SIZE);
        $list = FaUserModel::getUserList($page,$limit);
        $count = FaUserModel::getUserCount();

        $arr = [
            'count'=>$count,
            'list'=>$list
        ];
        return $arr;

    }


    public function del() : bool{
        $userId = $this->request->param('user_id',0);
        $del = FaUserModel::del($userId);
        return $del;
    }


    public function update() : bool {
        //
        $userData = $this->request->param();
        $update = FaUserModel::updateUser($userData);
        return $update;

    }

    public function create() : bool {
        //
        $userData = $this->request->param();

        $isExistsAccount = FaUserModel::getUserByAccount($userData['account']);

        if($isExistsAccount){
            throw new ObjectHasExists('account has exists');
        }
        $update = FaUserModel::createUser($userData);
        return $update;

    }


    public function logout(){

        $result = FaUserTokenModel::deleteTokenByUserId($this->userId);
        if($result) {
           Session::clear();
           throw new Success("");
        }else{
            // Unknow Error
            throw new Exception();
        }
    }

}